package com.buwei.module.rbac.domain.entity;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;

/*
@Data   ：注解在类上；提供类所有属性的 getting 和 setting 方法，此外还提供了equals、canEqual、hashCode、toString 方法
@Setter：注解在属性上；为属性提供 setting 方法
@Getter：注解在属性上；为属性提供 getting 方法
@Log4j ：注解在类上；为类提供一个 属性名为log 的 log4j 日志对象
@NoArgsConstructor：注解在类上；为类提供一个无参的构造方法
@AllArgsConstructor：注解在类上；为类提供一个全参的构造方法
*/
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table
public class User implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	Long id;
	
	@NotNull
	@Column(length = 20)
	String username;

	@NotNull
	@Size(min = 6, message = "密码长度至少为6位")
	String password;
	
	Boolean enabled;
	
	//当新增一个用户时，如果是关联已有的角色，只需要选择CascadeType.REFRESH，而不是CascadeType.ALL，
	//	选择ALL的场景是，你在新增用户的同时级联新增一个角色
	@ManyToOne(
			cascade = { CascadeType.REFRESH }, 
			fetch=FetchType.EAGER, 
			optional = true)
	@JoinColumn(
			name = "role_name", 
			nullable = true,
			referencedColumnName = "name",
			foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT))
	Role role;

	/**
	 * foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)
	 */
	/*
	@ManyToOne(
			cascade = { CascadeType.REFRESH }, 
			fetch=FetchType.EAGER, 
			optional = true)
	@JoinColumn(
			name = "department_id", 
			nullable = true,
			referencedColumnName = "id",
			foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT))
	Department department;
	*/
	
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
	@CreatedDate
    LocalDateTime createdAt;
    
    @CreatedBy
    String createdBy;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
    @LastModifiedDate
    LocalDateTime lastModifiedAt;
    
    @LastModifiedBy
    String lastModifiedBy;
    
    @PrePersist
    private void prePersist() throws UnsupportedEncodingException{
    	this.encodePassword(this.getPassword());
    }
    
    /**
     * @Description : 加密密码
     * ---------------------------------
     * @Author : Bu Wei
     * @Date : Created at 2018年4月30日 下午7:33:32
     */
    public void encodePassword(String password){
        BCryptPasswordEncoder encoder =new BCryptPasswordEncoder();
        this.setPassword(encoder.encode(this.getPassword().trim()));
    }
    
    /**
     * @Description : 检查传入密码与DB中是否匹配
     * ---------------------------------
     * @Author : Bu Wei
     * @Date : Created at 2018年1月22日 下午1:32:12
     */
    public Boolean checkPassword(String password){
    	BCryptPasswordEncoder encoder =new BCryptPasswordEncoder();
    	return encoder.matches(password, this.getPassword());
    }
    
    /**
     * @Description : 启用用户
     * ---------------------------------
     * @Author : Bu Wei
     * @Date : Created at 2018年4月30日 下午9:02:57
     */
	public User enable() {
		this.setEnabled(true);
		return this;
	}

	/**
	 * @Description : 停用用户
	 * ---------------------------------
	 * @Author : Bu Wei
	 * @Date : Created at 2018年4月30日 下午9:03:08
	 */
	public User disable() {
		this.setEnabled(false);
		return this;
	}
    
}
